import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Admin } from './entities/admin.entity';
import { Role } from '../role/entities/role.entity';
import { HashUtil } from '../../../common/utils/hash.util';
import { Permission } from '../permission/entities/permission.entity';
import { SaveMenuDto } from '../menu/dto/menu.dto';
import { Menu, MenuType } from '../menu/entities/menu.entity';
import { DataSource, IsNull } from 'typeorm';
import * as crypto from 'crypto';
import { DEFAULT_ROLE_VALUE } from '../../../common/constants/auth.constant';

/** 初始系统菜单数据 */
const sysMenus: SaveMenuDto[] = [
  {
    type: MenuType.MENU,
    name: '后台账号管理',
    path: 'account',
    order: 1,
    components: 'system/Account',
  },
  {
    type: MenuType.MENU,
    name: '角色管理',
    path: 'role',
    order: 2,
    components: 'system/Role',
  },
  {
    type: MenuType.MENU,
    name: '菜单管理',
    path: 'menu',
    order: 3,
    components: 'system/Menu',
  },
];
const sysCatalogueData: SaveMenuDto = {
  type: MenuType.CATALOGUE,
  name: '系统管理',
  path: '/system',
  order: 0,
  components: null,
};
@Injectable()
export class AdminInitializeService implements OnApplicationBootstrap {
  /** ROOT角色 */
  private readonly rootRoleValue: string;
  /** default admin email */
  private readonly adminEmail: string;
  /** 是否关闭初始化数据 */
  private readonly isClose: boolean;

  constructor(
    private readonly configService: ConfigService,
    private readonly dataSource: DataSource,
  ) {
    this.rootRoleValue = this.configService.get<string>(
      'ADMIN_ROLE_VALUE',
      DEFAULT_ROLE_VALUE,
    );
    this.adminEmail = this.configService.get<string>('ADMIN_EMAIL');
    this.isClose = this.configService.get('CLOSE_INIT_DATA') === 'true';
  }

  async onApplicationBootstrap() {
    if (!this.isClose) {
      await this.initializeSysMenus();
      await this.initializeRootRole();
      await this.initializeAdmin();
    }
  }

  /**
   * 初始化系统管理目录及菜单
   */
  private async initializeSysMenus() {
    const MenuRepository = this.dataSource.getRepository(Menu);
    const sysCatalogue = await MenuRepository.findOneBy({
      type: MenuType.CATALOGUE,
      path: sysCatalogueData.path,
      components: IsNull(),
    });
    if (!sysCatalogue) {
      const sysCatalogueId = sysCatalogue?.id ?? crypto.randomUUID();
      const saveMenus: Menu[] = [];
      saveMenus.push(
        MenuRepository.create({
          ...sysCatalogueData,
          id: sysCatalogueId,
        }),
      );
      for (const menu of sysMenus) {
        saveMenus.push(
          MenuRepository.create({
            ...menu,
            parentId: sysCatalogueId,
          }),
        );
      }
      if (saveMenus.length) {
        await Menu.save(saveMenus);
      }
    }
  }

  /**
   * 初始化ROOT角色
   */
  private async initializeRootRole() {
    const permissions = await Permission.find();
    const menus = await Menu.find();
    const role = await Role.findOneBy({
      value: this.rootRoleValue,
    });
    if (!role) {
      await Role.save({
        name: this.configService.get<string>('ADMIN_ROLE_NAME', '管理员'),
        value: this.rootRoleValue,
        permissions,
        menus,
      });
    } else {
      await Role.save({
        ...role,
        permissions,
        menus,
      });
    }
  }

  /**
   * 初始化后台管理员账户
   */
  private async initializeAdmin() {
    const admin = await Admin.findOneBy({
      email: this.adminEmail,
    });
    const roles = await Role.find({
      where: { value: this.rootRoleValue },
    });
    if (!admin) {
      await Admin.save(
        Admin.create({
          email: this.adminEmail,
          password: HashUtil.encryption(
            this.configService.get<string>('ADMIN_PASSWORD', '12345678'),
          ),
          username: this.configService.get<string>(
            'ADMIN_USERNAME',
            '超级管理员',
          ),
          roles,
        }),
      );
    } else {
      await Admin.save({
        ...admin,
        roles,
      });
    }
  }
}
